#coding:utf-8

import time
import sys
import types
import traceback
import linecache
    
class Failure(Exception):
    def __str__(self):
        return self.message
    __repr__ = __str__

class Warning(Exception):
    pass

class RunningExceptoin(Exception):
    def __str__(self):
        time.strftime(format)

class HasNotThisArgument(Exception):
    pass

class ParserError(Exception):
    def __init__(self, type, fpath, msg):
        self.type = type
        self.fpath = fpath
        self.error_msg = msg
        Exception.__init__(self, "%s parser error: %s[%s]"%(type, fpath, msg))

def last_error_message():
    return str(sys.exc_info()[1])

def last_error():
    return sys.exc_info()

def format_error_message(etype, value):
    return "%s: %s"%(etype.__name__, value)

def is_core_module(tb):
    return tb.tb_frame.f_globals.has_key('__TEST__')

def get_locals(tb):
    vars = tb.tb_frame.f_locals
    args_object = vars.pop('args', None)
    if isinstance(args_object, types.DictType):
        for key in args_object:
            vars["args.%s"%key] = getattr(args_object, key)
    new_vars = {}
    for key, value in vars.iteritems():
        if isinstance(key, types.ModuleType): # dont need module
            continue
        new_vars[key] = value
    return new_vars

def format_exception(exctype, value, tb):
    msg_list = []
    tb_list = []
    # if exc type is Failure or Warning type, core code is blocked for user
    if exctype in (Failure, Warning):
        while tb:
            if not is_core_module(tb):
                tb_list.append(tb)
            tb = tb.tb_next
    else:
        while tb:
            tb_list.append(tb)
            tb = tb.tb_next
    for tb in tb_list:
        lineno = tb.tb_lineno
        fpath = tb.tb_frame.f_code.co_filename
        funcname = tb.tb_frame.f_code.co_name
        linecache.checkcache(fpath)
        text = linecache.getline(fpath, lineno, tb.tb_frame.f_globals)
        text = text.strip() if text else None
        msg = "%s in %d, %s:  %s"%(fpath, lineno, funcname, text)
        env = get_locals(tb)
        msg_list.append((msg, env))
    # add error message
    msg_list.append((format_error_message(exctype, value), {}))
    return msg_list